home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / mus / misc / normalize.lha / bin / normalize-mp3 next >
Encoding:
Text File  |  2002-02-21  |  15.9 KB  |  606 lines

  1. #! /gg/bin/perl -w
  2. # -*- perl -*-
  3. # Copyright (C) 1999--2002 Chris Vaill
  4. # This file is part of normalize.
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2, or (at your option)
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.  
  21. #######################################################################
  22. # These variables may be customized for local setup
  23. #######################################################################
  24.  
  25. # %m becomes name of mp3 or ogg file
  26. # %w becomes name of temporary WAV file
  27. # %b becomes bitrate of re-encoded file, as specified by the -b option
  28. # Example: $OGGENCODE="oggenc -Q -b %b -o %m %w"
  29.  
  30. $MP3DECODE = "REPLACE_WITH_MP3_DECODER -q -o %w %m";
  31. $MP3ENCODE = "REPLACE_WITH_MP3_ENCODER -quiet %w %m";
  32. $OGGDECODE = "REPLACE_WITH_OGG_DECODER -q -d wav -f %w %m";
  33. $OGGENCODE = "REPLACE_WITH_OGG_ENCODER -Q -b %b -o %m %w";
  34.  
  35. $VORBISCOMMENT = "REPLACE_WITH_VORBISCOMMENT";
  36.  
  37. # change this if normalize is not on your path
  38. $NORMALIZE = "normalize";
  39.  
  40.  
  41. #######################################################################
  42. # No user serviceable parts below
  43. #######################################################################
  44.  
  45. use Fcntl;
  46.  
  47. sub usage {
  48.     print <<EOF
  49. Usage: $progname [OPTION]... [FILE]...
  50.   Normalize volume of mp3 or ogg files by decoding, running normalize,
  51.   and re-encoding.  This requires as much extra disk space as the
  52.   largest mp3 or ogg file, decoded.  Note that for batch and mix mode,
  53.   all files must be decoded, so there must be enough disk space for
  54.   the decoded copies of all specified mp3 and ogg files.
  55.  
  56.   -a AMP         \\
  57.   -g ADJ          |
  58.   -n              |
  59.   -T THR          |_ These arguments are passed as arguments to normalize.
  60.   -b              |  Run "normalize --help" for more info.
  61.   -m              |
  62.   -v              |
  63.   -q             /
  64.  
  65.   --bitrate BR   Set bitrate of re-encoded file [default 128]
  66.   --ogg          Convert files to ogg, regardless of original format
  67.   --mp3          Convert files to mp3, regardless of original format
  68.   --tmpdir TMP   Put temporary WAV files in temp directory TMP
  69.   --notags       Do not copy ID3 or ogg tags to the output file
  70.   --backup       Keep backups of original files, suffixed with '~'
  71.  
  72.   The following four options may be used to set the encoder and
  73.   decoder commands for mp3 and ogg vorbis.  \%m is expanded to the
  74.   name of the mp3 or vorbis file, \%w expands to the name of the
  75.   temporary WAV file, and \%b expands to the bitrate, as specified by
  76.   the --bitrate option.  The default values are shown in brackets
  77.   below.
  78.  
  79.   --mp3encode=X  mp3 encoder        [$MP3ENCODE]
  80.   --mp3decode=X  mp3 decoder        [$MP3DECODE]
  81.   --oggencode=X  ogg vorbis encoder [$OGGENCODE]
  82.   --oggdecode=X  ogg vorbis decoder [$OGGDECODE]
  83.  
  84.   -h             Display this help and exit.
  85.   -V             Display version information and exit.
  86.  
  87. Report bugs to <cvaill\@cs.columbia.edu>.
  88. EOF
  89. }
  90.  
  91.  
  92. # same effect as a backtick, but shell metacharacters are not expanded
  93. sub backtick_noshell {
  94.     my @args = @_;
  95.     my $retval = "";
  96.     defined(my $pid = open(BABY, "-|")) || die "Can't fork: $!";
  97.     if ($pid) {
  98.     local $SIG{INT} = 'IGNORE';
  99.     while (<BABY>) {
  100.         $retval .= $_;
  101.     }
  102.     close BABY;
  103.     } else {
  104.     exec(@args) || die "Can't exec $args[0]";
  105.     }
  106.     $retval;
  107. }
  108.  
  109.  
  110. sub read_tags {
  111.     my ($fname) = @_;
  112.     my ($retval, $vorbis_tag, $id3v1_tag, $id3v2_tag, $id3v2_sz);
  113.  
  114.     if ($fname =~ /\.ogg$/i) {
  115.     $vorbis_tag = backtick_noshell($VORBISCOMMENT, $fname);
  116.     defined($vorbis_tag) || die "Can't run vorbiscomment: $!";
  117.     $retval = [ 'ogg', $vorbis_tag ];
  118.  
  119.     } elsif ($fname =~ /\.mp3$/i) {
  120.     open(IN, $fname) || die "Can't read $fname: $!";
  121.     # read ID3v2 tag, if it's there
  122.     # FIXME: doesn't work for ID3v2.4.0 appended tags
  123.     read(IN, $id3v2_tag, 3);
  124.     if ($id3v2_tag eq "ID3") {
  125.         read(IN, $id3v2_tag, 7, 3);
  126.         # figure tag size
  127.         my ($x1, $x2, $x3, $x4) = unpack("x6 C C C C", $id3v2_tag);
  128.         my $tagsz = $x1;
  129.         $tagsz <<= 7;
  130.         $tagsz += $x2;
  131.         $tagsz <<= 7;
  132.         $tagsz += $x3;
  133.         $tagsz <<= 7;
  134.         $tagsz += $x4;
  135.         read(IN, $id3v2_tag, $tagsz, 10);
  136.         $id3v2_sz = $tagsz + 10;
  137.     } else {
  138.         undef $id3v2_tag;
  139.         $id3v2_sz = 0;
  140.     }
  141.     # read ID3v1 tag, if it's there
  142.     seek(IN, -128, 2);
  143.     read(IN, $id3v1_tag, 3);
  144.     if ($id3v1_tag eq "TAG") {
  145.         read(IN, $id3v1_tag, 125, 3);
  146.     } else {
  147.         undef $id3v1_tag;
  148.     }
  149.     close(IN);
  150.  
  151.     $retval = [ 'id3', $id3v1_tag, $id3v2_tag, $id3v2_sz ];
  152.     }
  153.  
  154.     $retval;
  155. }
  156.  
  157.  
  158. sub write_tags {
  159.     my ($fname, $tag) = @_;
  160.  
  161.     if ($fname =~ /\.ogg$/i) {
  162.     if ($tag->[0] eq 'ogg' && $tag->[1]) {
  163.         my @args = ($VORBISCOMMENT, "-a", $fname);
  164.         defined(my $pid = open(BABY, "|-")) || die "Can't fork: $!";
  165.         if ($pid) {
  166.         local $SIG{INT} = 'IGNORE';
  167.         print BABY $tag->[1];
  168.         close BABY;
  169.         $? == 0 || die "Error running vorbiscomment, stopped";
  170.         } else {
  171.         exec(@args) || die "Can't run vorbiscomment: $!";
  172.         }
  173.  
  174.     }
  175.  
  176.     } elsif ($fname =~ /\.mp3$/i) {
  177.     if ($tag->[0] eq 'id3' && $tag->[1]) {
  178.         my $id3v1_tag = $tag->[1];
  179.         open(OUT, ">>".$fname)
  180.         || die "Can't append tag to $fname: $!, stopped";
  181.         syswrite(OUT, $id3v1_tag, 128);
  182.         close(OUT);
  183.     }
  184.     if ($tag->[0] eq 'id3' && $tag->[2]) {
  185.         my ($buf, $tmpfile);
  186.         my $id3v2_tag = $tag->[2];
  187.         my $id3v2_sz = $tag->[3];
  188.         my $n = $$;
  189.         while (1) {
  190.         $tmpfile = $tmpdir.$progname."-".$n.".tag";
  191.         if (sysopen(OUT, $tmpfile, O_WRONLY|O_CREAT|O_EXCL)) {
  192.             last;
  193.         }
  194.         $! == EEXIST || die "Can't write $tmpfile: $!, stopped";
  195.         $n++;
  196.         }
  197.         syswrite(OUT, $id3v2_tag, $id3v2_sz);
  198.         open(IN, $fname) || die "Can't read $fname: $!, stopped";
  199.         while ($ret = sysread(IN, $buf, 4096)) {
  200.         syswrite(OUT, $buf, $ret);
  201.         }
  202.         close(IN);
  203.         close(OUT);
  204.         unlink $fname;
  205.         rename($tmpfile, $fname)
  206.         || die "Can't rename temp file, leaving in $tmpfile, stopped";
  207.     }
  208.     }
  209. }
  210.  
  211.  
  212. ($progname = $0) =~ s/.*\///;
  213. $version = "0.7.2";
  214. $nomoreoptions = 0;
  215.  
  216. unless ($ARGV[0]) {
  217.     usage();
  218.     exit 0;
  219. }
  220.  
  221. # default option values
  222. @normalize_args = ($NORMALIZE, "--frontend", "-T", "0.25");
  223. $all_to_mp3 = 0;
  224. $all_to_ogg = 0;
  225. $bitrate = 128;
  226. $do_copy_tags = 1;
  227. $tmpdir = "";
  228. $do_adjust = 1;
  229. $batch_mode = 0;
  230. $mix_mode = 0;
  231. $keep_backups = 0;
  232. # we track verbosity separately for this script
  233. $verbose = 1;
  234.  
  235. if ($VORBISCOMMENT =~ /^REPLACE/) {
  236.     undef $VORBISCOMMENT;
  237. }
  238.  
  239. @infnames = ();
  240.  
  241. # step through arguments
  242. $nomoreoptions = 0;
  243. ARG_LOOP:
  244. while ($ARGV[0]) {
  245.     if ($ARGV[0] =~ /^-/ && !$nomoreoptions) {
  246.     $_ = $ARGV[0];
  247.  
  248.     if ($_ eq "-a" || $_ eq "--amplitude") {
  249.         push @normalize_args, "-a", $ARGV[1];
  250.         shift; shift; next ARG_LOOP;
  251.     } elsif ($_ eq "--bitrate") {
  252.         $bitrate = $ARGV[1];
  253.         shift; shift; next ARG_LOOP;
  254.     } elsif ($_ eq "-g" || $_ eq "--gain") {
  255.         push @normalize_args, "-g", $ARGV[1];
  256.         shift; shift; next ARG_LOOP;
  257.     } elsif ($_ eq "-n" || $_ eq "--no-adjust") {
  258.         push @normalize_args, "-n";
  259.         $do_adjust = 0;
  260.         shift; next ARG_LOOP;
  261.     } elsif ($_ eq "-T" || $_ eq "--adjust-threshold") {
  262.         push @normalize_args, "-T", $ARGV[1];
  263.         shift; shift; next ARG_LOOP;
  264.     } elsif ($_ eq "--tmp" || $_ eq "--tmpdir") {
  265.         $tmpdir = $ARGV[1];
  266.         if ($tmpdir !~ /\/$/) {
  267.         $tmpdir = $tmpdir."/";
  268.         }
  269.         shift; shift; next ARG_LOOP;
  270.     } elsif ($_ eq "-v" || $_ eq "--verbose") {
  271.         push @normalize_args, "-v";
  272.         $verbose = 2;
  273.         shift; next ARG_LOOP;
  274.     } elsif ($_ eq "-b" || $_ eq "--batch") {
  275.         push @normalize_args, "-b";
  276.         $batch_mode = 1;
  277.         shift; next ARG_LOOP;
  278.     } elsif ($_ eq "-m" || $_ eq "--mix") {
  279.         push @normalize_args, "-m";
  280.         $mix_mode = 1;
  281.         shift; next ARG_LOOP;
  282.     } elsif ($_ eq "-q" || $_ eq "--quiet") {
  283.         push @normalize_args, "-q";
  284.         $verbose = 0;
  285.         shift; next ARG_LOOP;
  286.     } elsif ($_ eq "--ogg") {
  287.         $all_to_ogg = 1;
  288.         $all_to_mp3 = 0;
  289.         shift; next ARG_LOOP;
  290.     } elsif ($_ eq "--mp3") {
  291.         $all_to_mp3 = 1;
  292.         $all_to_ogg = 0;
  293.         shift; next ARG_LOOP;
  294.     } elsif ($_ eq "--backup") {
  295.         $keep_backups = 1;
  296.         shift; next ARG_LOOP;
  297.     } elsif ($_ eq "--notags" || $_ eq "--noid3") {
  298.         $do_copy_tags = 0;
  299.         shift; next ARG_LOOP;
  300.     } elsif ($_ eq "-h" || $_ eq "--help") {
  301.         usage;
  302.         exit 0;
  303.     } elsif ($_ eq "-V" || $_ eq "--version") {
  304.         print "$progname (normalize) $version\n";
  305.         exit 0;
  306.     } elsif ($_ eq "--") {
  307.         $nomoreoptions = 1;
  308.         shift; next ARG_LOOP;
  309.     } else {
  310.         print "Unrecognized option \"",$ARGV[0],"\"\n";
  311.         usage;
  312.         exit 1;
  313.     }
  314.     }
  315.  
  316.     push(@infnames, shift);
  317. }
  318.  
  319. if ($batch_mode || $mix_mode) {
  320.  
  321.     #
  322.     # decode all files
  323.     #
  324.     @tmpfnames = ();
  325.     @outfnames = ();
  326.     for($i = 0; $i <= $#infnames; $i++) {
  327.     $input_file = $infnames[$i];
  328.  
  329.     if ($input_file =~ /\.mp3$/i) {
  330.         $decoder = $MP3DECODE;
  331.     } elsif ($input_file =~ /\.ogg$/i) {
  332.         $decoder = $OGGDECODE;
  333.     } else {
  334.         print STDERR "$progname: $input_file has unrecognized extension\n";
  335.         print STDERR "$progname: Recognized extensions are mp3 and ogg\n";
  336.         splice(@infnames, $i, 1);
  337.         $i--;
  338.         next;
  339.     }
  340.  
  341.     # construct temporary file name
  342.     #   NOTE: There is a race condition here, similar to the C
  343.     #   tmpnam() function.  We are ignoring it.
  344.     ($filebase = $input_file) =~ s/^.*\///;
  345.     $filebase = $tmpdir.$filebase;
  346.     $n = $$;
  347.     do {
  348.         $tmp_file = $filebase.".".$n.".wav";
  349.         $n++;
  350.     } while (-e $tmp_file);
  351.     push(@tmpfnames, $tmp_file);
  352.     # construct output file name
  353.     ($filebase = $input_file) =~ s/\..*?$//;
  354.     if ($all_to_mp3) {
  355.         $output_file = $filebase.".mp3";
  356.     } elsif ($all_to_ogg) {
  357.         $output_file = $filebase.".ogg";
  358.     } else {
  359.         $output_file = $input_file;
  360.     }
  361.     push(@outfnames, $output_file);
  362.  
  363.     # construct decode command
  364.     @decode_args = split(/\s+/, $decoder);
  365.     for (@decode_args) {
  366.         s/^\%w$/$tmp_file/;
  367.         s/^\%m$/$input_file/;
  368.         s/^\%b$/$bitrate/;
  369.     }
  370.  
  371.     # save tags
  372.     $do_copy_tags && ($tagref = read_tags($input_file));
  373.     push(@tags, $tagref);
  374.  
  375.     # run decoder
  376.     $verbose > 0 && print STDERR "Decoding $input_file...\n";
  377.     if ($verbose < 2) {
  378.         open(OLDOUT, ">&STDOUT");
  379.         open(STDOUT, ">/dev/null") || die "Can't redirect stdout";
  380.     }
  381.     $ret = system(@decode_args);
  382.     if ($verbose < 2) {
  383.         close(STDOUT);
  384.         open(STDOUT, ">&OLDOUT");
  385.     }
  386.     $ret == 0 || die "Error decoding, stopped";
  387.     }
  388.  
  389.  
  390.     #
  391.     # normalize all files
  392.     #
  393.     $verbose > 0 && print STDERR "Running normalize...\n";
  394.     @args = (@normalize_args, @tmpfnames);
  395.     $adjust_needed = 1;
  396.     defined($pid = open(NORM, "-|")) || die "Can't fork: $!";
  397.     if ($pid) {
  398.     local $SIG{INT} = 'IGNORE';
  399.     $dummy = 0; # suppress warnings about single use
  400.     while (<NORM>) {
  401.         if (/^ADJUST_NEEDED /) {
  402.         ($dummy, $adjust_needed) = split;
  403.         } elsif (/^LEVEL /) {
  404.         unless ($do_adjust) {
  405.             # with -n specified, the line following a LEVEL line
  406.             # is the "level peak gain" line, so print it out
  407.             $_ = <NORM>;
  408.             print;
  409.         }
  410.         }
  411.     }
  412.     close NORM;
  413.     $? == 0 || die "Error during normalize, stopped";
  414.     } else {
  415.     exec(@args) || die "Can't run normalize: $!";
  416.     }
  417.  
  418.  
  419.     #
  420.     # re-encode all files
  421.     #
  422.     if ($do_adjust) {
  423.     for($i = 0; $i <= $#infnames; $i++) {
  424.         $input_file  = $infnames[$i];
  425.         $output_file = $outfnames[$i];
  426.         $tmp_file    = $tmpfnames[$i];
  427.         $tagref      = $tags[$i];
  428.  
  429.         # construct encode command
  430.         $encoder = ($output_file =~ /\.ogg$/i) ? $OGGENCODE : $MP3ENCODE;
  431.         @encode_args = split(/\s+/, $encoder);
  432.         for (@encode_args) {
  433.         s/^\%w$/$tmp_file/;
  434.         s/^\%m$/$output_file/;
  435.         s/^\%b$/$bitrate/;
  436.         }
  437.  
  438.         if ($adjust_needed || $input_file ne $output_file) {
  439.         if ($keep_backups) {
  440.             rename($input_file, $input_file."~");
  441.         } else {
  442.             unlink($input_file);
  443.         }
  444.         # run encoder
  445.         $verbose > 0 && print STDERR "Re-encoding $input_file...\n";
  446.         if ($verbose < 2) {
  447.             open(OLDOUT, ">&STDOUT");
  448.             open(STDOUT, ">/dev/null") || die "Can't redirect stdout";
  449.         }
  450.         $ret = system(@encode_args);
  451.         if ($verbose < 2) {
  452.             close(STDOUT);
  453.             open(STDOUT, ">&OLDOUT");
  454.         }
  455.         $ret == 0 || die "Error encoding, stopped";
  456.         } else {
  457.         $verbose > 0 && print "$input_file is already normalized, not re-encoding...\n";
  458.         }
  459.  
  460.         # restore tags, if necessary
  461.         $do_copy_tags && write_tags($output_file, $tagref);
  462.  
  463.         # delete temp file
  464.         unlink $tmp_file || print STDERR "Can't remove $tmp_file: $!\n";
  465.     }
  466.     }
  467.  
  468.     exit 0;
  469. }
  470.  
  471.  
  472. #
  473. # not mix or batch mode
  474. #
  475. for $input_file (@infnames) {
  476.  
  477.     if ($input_file =~ /\.mp3$/i) {
  478.     $decoder = $MP3DECODE; $encoder = $MP3ENCODE;
  479.     } elsif ($input_file =~ /\.ogg$/i) {
  480.     $decoder = $OGGDECODE; $encoder = $OGGENCODE;
  481.     } else {
  482.     print STDERR "$progname: $input_file has unrecognized extension\n";
  483.     print STDERR "$progname: Recognized extensions are mp3 and ogg\n";
  484.     next;
  485.     }
  486.  
  487.     # construct temporary file name
  488.     #   NOTE: There is a race condition here, similar to the C
  489.     #   tmpnam() function.  We are ignoring it.
  490.     ($filebase = $input_file) =~ s{^.*/}{};
  491.     $filebase = $tmpdir.$filebase;
  492.     $n = $$;
  493.     do {
  494.     $tmp_file = $filebase.".".$n.".wav";
  495.     $n++;
  496.     } while (-e $tmp_file);
  497.     # construct output file name
  498.     #($filebase = $input_file) =~ s{(.*/)?(.*)\..*}{$2};
  499.     ($filebase = $input_file) =~ s{\..*?$}{};
  500.     if ($all_to_mp3) {
  501.     $output_file = $filebase.".mp3";
  502.     $encoder = $MP3ENCODE;
  503.     } elsif ($all_to_ogg) {
  504.     $output_file = $filebase.".ogg";
  505.     $encoder = $OGGENCODE;
  506.     } else {
  507.     $output_file = $input_file;
  508.     }
  509.  
  510.     # construct encode and decode commands
  511.     @decode_args = split(/\s+/, $decoder);
  512.     for (@decode_args) {
  513.     s/^\%w$/$tmp_file/;
  514.     s/^\%m$/$input_file/;
  515.     s/^\%b$/$bitrate/;
  516.     }
  517.     @encode_args = split(/\s+/, $encoder);
  518.     for (@encode_args) {
  519.     s/^\%w$/$tmp_file/;
  520.     s/^\%m$/$input_file/;
  521.     s/^\%b$/$bitrate/;
  522.     }
  523.  
  524.     # save tags
  525.     $do_copy_tags && ($tagref = read_tags($input_file));
  526.  
  527.  
  528.     #
  529.     # run decoder
  530.     #
  531.     $verbose > 0 && print STDERR "Decoding $input_file...\n";
  532.     if ($verbose < 2) {
  533.     open(OLDOUT, ">&STDOUT");
  534.     open(STDOUT, ">/dev/null") || die "Can't redirect stdout";
  535.     }
  536.     $ret = system(@decode_args);
  537.     if ($verbose < 2) {
  538.     close(STDOUT);
  539.     open(STDOUT, ">&OLDOUT");
  540.     }
  541.     $ret == 0 || die "Error decoding, stopped";
  542.  
  543.  
  544.     #
  545.     # run normalize
  546.     #
  547.     $verbose > 0 && print STDERR "Running normalize...\n";
  548.     @args = (@normalize_args, $tmp_file);
  549.     $adjust_needed = 1;
  550.     defined($pid = open(NORM, "-|")) || die "Can't fork: $!";
  551.     if ($pid) {
  552.     local $SIG{INT} = 'IGNORE';
  553.     $dummy = 0; # suppress warnings about single use
  554.     while (<NORM>) {
  555.         if (/^ADJUST_NEEDED /) {
  556.         ($dummy, $adjust_needed) = split;
  557.         } elsif (/^LEVEL /) {
  558.         unless ($do_adjust) {
  559.             # with -n specified, the line following a LEVEL line
  560.             # is the "level peak gain" line, so print it out
  561.             $_ = <NORM>;
  562.             print;
  563.         }
  564.         }
  565.     }
  566.     close NORM;
  567.     $? == 0 || die "Error during normalize, stopped";
  568.     } else {
  569.     exec(@args) || die "Can't run normalize: $!";
  570.     }
  571.  
  572.  
  573.     #
  574.     # run encoder, if necessary
  575.     #
  576.     if ($do_adjust) {
  577.     if ($adjust_needed || $input_file ne $output_file) {
  578.         if ($keep_backups) {
  579.         rename($input_file, $input_file."~");
  580.         } else {
  581.         unlink($input_file);
  582.         }
  583.         # run encoder
  584.         $verbose > 0 && print STDERR "Re-encoding $input_file...\n";
  585.         if ($verbose < 2) {
  586.         open(OLDOUT, ">&STDOUT");
  587.         open(STDOUT, ">/dev/null") || die "Can't redirect stdout";
  588.         }
  589.         $ret = system(@encode_args);
  590.         if ($verbose < 2) {
  591.         close(STDOUT);
  592.         open(STDOUT, ">&OLDOUT");
  593.         }
  594.         $ret == 0 || die "Error encoding, stopped";
  595.     } else {
  596.         $verbose > 0 && print "$input_file is already normalized, not re-encoding...\n";
  597.     }
  598.     }
  599.  
  600.     # restore tags, if necessary
  601.     $do_copy_tags && write_tags($output_file, $tagref);
  602.  
  603.     # delete temp file
  604.     unlink $tmp_file || print STDERR "Can't remove $tmp_file: $!\n";
  605. }
  606.